package glemipsc.instructions;

import glemipsc.Address;
import glemipsc.Function;
import glemipsc.GLEMipsC;
import glemipsc.Type;
import glemipsc.implementations.Argument;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class If extends BaseInstruction implements Serializable, Instruction, Expression {
	private Expression condition;
	private ArrayList trueInstructions;
	private ArrayList falseInstructions = null;
	private Address addr;
	
	public If(Expression condition, ArrayList trueInstructions) {
		this.condition = condition;
		this.trueInstructions = trueInstructions;
		Iterator iter = trueInstructions.iterator();
		while (iter.hasNext()) {
			Instruction instr = (Instruction) iter.next();
			instr.setParent(this);
		}
	}
	
	public If(Expression condition, ArrayList trueInstructions, ArrayList falseInstructions) {
		this.condition = condition;
		this.trueInstructions = trueInstructions;
		this.falseInstructions = falseInstructions;
		Iterator iter = trueInstructions.iterator();
		while (iter.hasNext()) {
			Instruction instr = (Instruction) iter.next();
			instr.setParent(this);
		}
		iter = falseInstructions.iterator();
		while (iter.hasNext()) {
			Instruction instr = (Instruction) iter.next();
			instr.setParent(this);
		}
	}
	
	public void setFalseInstructions(ArrayList falseInstructions) {
		this.falseInstructions = falseInstructions;
	}
	
	public Expression getOperand(int index) {
		if (index == 0)
			return condition;
		return null;
	}
	
	public int getNumberOfOperands() {
		return 1;
	}

	public int getSize() {
		return 0;
	}

	public Type getType() {
		return Type.createFromName("void");
	}

	public int getImmediateValue() {
		return 0;
	}

	public boolean isImmediate() {
		return false;
	}

	public Address getStoreAddress() {
		return addr;
	}

	public int getStoredSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	public boolean isStored() {
		return true;
	}

	public void setStoreAddress(Address addr) {
		this.addr = addr;
	}

	public void computeInstruction(Argument result, List<glemipsc.implementations.Instruction> instructions, Function func) {
		glemipsc.implementations.Implementation impl = GLEMipsC.compiler.getEnvironment().implementation;
		Argument tmp = impl.getFreeRegister();
		condition.computeInstruction(tmp, instructions, func);
		ArrayList<glemipsc.implementations.Instruction> instrTrue = new ArrayList<glemipsc.implementations.Instruction>();
		Iterator iter = this.trueInstructions.iterator();
		while (iter.hasNext()) {
			Instruction instr = (Instruction) iter.next();
			instr.computeInstruction(result, instrTrue, func);
		}
		ArrayList<glemipsc.implementations.Instruction> instrFalse = new ArrayList<glemipsc.implementations.Instruction>();
		if (falseInstructions != null) {
			iter = this.falseInstructions.iterator();
			while (iter.hasNext()) {
				Instruction instr = (Instruction) iter.next();
				instr.computeInstruction(result, instrFalse, func);
			}
			instrTrue.add(impl.getJnz(tmp, impl.getImmediate(getInstructionsSize(instrFalse))));
		}
		instructions.add(impl.getJz(tmp, impl.getImmediate(getInstructionsSize(instrTrue))));
		instructions.addAll(instrTrue);
		instructions.addAll(instrFalse);
		impl.freeRegister(tmp);
	}

}
